const { ccclass, property } = cc._decorator;

/**
 * 状态动作基类
 * 所有状态必须继承此类
 */
export abstract class FSMAction {
  constructor(public readonly id: string) {}

  /**
   * 进入状态时调用
   * 可以是异步操作（如播放动画、加载资源）
   * @param fsm - 当前状态机实例
   * @param data - 额外传递的数据
   */
  onEnter(fsm: FSM, data?: any): void | Promise<void> {}

  /**
   * 每帧更新（fixedUpdate 触发）
   * 可返回 Promise 表示仍在执行
   * @param fsm - 状态机
   * @param dt - 自状态进入后的累计时间（秒）
   * @param data - 额外数据
   */
  onUpdate(
    fsm: FSM,
    dt: number,
    data?: any
  ): void | boolean | Promise<void | boolean> {}

  /**
   * 退出状态时调用
   * 可用于清理资源、重置属性
   * @param fsm - 状态机
   * @param data - 额外数据
   */
  onExit(fsm: FSM, data?: any): void | Promise<void> {}
}

/**
 * 条件转移定义
 * 当条件返回 true 时，自动切换到目标状态
 */
export type TransitionCondition = {
  toStateId: string; // 目标状态 ID
  condition: (fsm: FSM) => boolean; // 判断条件函数
  priority?: number; // 优先级（数字越大越优先，默认 0）
};

/**
 * 事件转移定义
 * 当指定事件触发时，切换到目标状态
 */
export type EventTransition = {
  event: string; // 监听的事件名
  toStateId: string; // 目标状态 ID
  filter?: (fsm: FSM, eventData?: any) => boolean; // 可选过滤器
};

/**
 * 有限状态机（FSM）
 * 支持异步状态、条件转移、事件驱动
 */
@ccclass
export default class FSM extends cc.Component {
  // 当前状态
  private curr: FSMAction | null = null;
  // 上一个状态
  private prev: FSMAction | null = null;
  // 绑定的目标对象（通常是挂载此组件的节点或逻辑对象）
  private _target: any = null;
  // 自当前状态进入以来经过的时间（秒）
  private timeElapsed: number = 0;
  // 所有注册的状态，使用 Map 更安全
  private states = new Map<string, FSMAction>();
  // 是否暂停更新
  private _isPaused: boolean = false;
  // 是否运行中
  private _running: boolean = true;
  // 当前是否正在处理异步状态切换
  private isTransitioning: boolean = false;
  // 条件转移规则列表
  private conditions: TransitionCondition[] = [];
  // 事件转移映射表：event -> transitions[]
  private eventTransitions = new Map<string, EventTransition[]>();

  // ------------------ Getter ------------------

  /**
   * 获取当前状态机绑定的目标对象
   */
  get target(): any {
    return this._target;
  }

  /**
   * 获取当前状态
   */
  getCurrState(): FSMAction | null {
    return this.curr;
  }

  /**
   * 获取上一个状态
   */
  getPrevState(): FSMAction | null {
    return this.prev;
  }

  /**
   * 获取指定 ID 的状态
   * @param id 状态 ID
   * @returns 状态实例或 null
   */
  getState(id: string): FSMAction | null {
    return this.states.get(id) || null;
  }

  // ------------------ 初始化与生命周期 ------------------

  /**
   * 初始化状态机
   * @param target 绑定的目标对象（如角色节点、AI 控制器等）
   */
  init(target: any): void {
    this._target = target;
    this.curr = null;
    this.prev = null;
    this.timeElapsed = 0;
    this.conditions = [];
    this.eventTransitions.clear();
    this.states.clear();
    this.isTransitioning = false;
  }

  /**
   * 添加一个状态到状态机
   * @param action 状态实例
   */
  addState(action: FSMAction): void {
    this.states.set(action.id, action);
  }

  /**
   * 移除一个状态
   * @param id 状态 ID
   */
  removeState(id: string): void {
    this.states.delete(id);
  }

  // ------------------ 状态切换 ------------------

  /**
   * 异步切换到指定状态
   * 支持 onExit 和 onEnter 为异步函数
   * @param id 目标状态 ID
   * @param force 是否强制切换（即使已是当前状态）
   * @param data 传递给 onEnter/onExit 的额外数据
   */
  async changeState(
    id: string,
    force: boolean = false,
    data?: any
  ): Promise<void> {
    if (this.isTransitioning) {
      cc.warn(`[FSM] 正在切换状态，忽略切换到 ${id}`);
      return;
    }

    const nextState = this.states.get(id);
    if (!nextState && id !== null) {
      cc.warn(`[FSM] 未找到状态: ${id}`);
      return;
    }

    // 如果当前已是该状态且不强制，则不切换
    if (this.curr && this.curr.id === id && !force) {
      return;
    }

    this.isTransitioning = true;

    // 退出当前状态
    if (this.curr) {
      const exitPromise = this.curr.onExit(this, data);
      if (exitPromise instanceof Promise) {
        await exitPromise;
      }
    }

    // 更新状态
    this.prev = this.curr;
    this.curr = nextState;
    this.timeElapsed = 0;

    // 进入新状态
    if (this.curr) {
      const enterPromise = this.curr.onEnter(this, data);
      if (enterPromise instanceof Promise) {
        await enterPromise;
      }
    }

    this.isTransitioning = false;
    cc.log(
      `[FSM] 状态切换完成: ${this.prev?.id ?? "null"} → ${
        this.curr?.id ?? "null"
      }`
    );
  }

  /**
   * 重新进入当前状态（相当于重置）
   * 会触发 onExit → onEnter
   */
  async resetCurrentState(data?: any): Promise<void> {
    if (this.curr) {
      await this.changeState(this.curr.id, true, data);
    }
  }

  /**
   * 返回上一个状态
   */
  async revertState(data?: any): Promise<void> {
    if (this.prev) {
      await this.changeState(this.prev.id, false, data);
    } else {
      cc.warn("[FSM] 没有上一个状态可返回");
    }
  }

  // ------------------ 条件转移 ------------------

  /**
   * 添加一个条件转移规则
   * @param condition 条件对象
   */
  addCondition(condition: TransitionCondition): void {
    this.conditions.push(condition);
    // 按优先级排序（高优先级在前）
    this.conditions.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
  }

  /**
   * 移除所有指定目标状态的条件
   */
  removeConditionByTarget(toStateId: string): void {
    this.conditions = this.conditions.filter((c) => c.toStateId !== toStateId);
  }

  // ------------------ 事件驱动 ------------------

  /**
   * 监听一个事件并绑定状态转移
   * @param event 事件名
   * @param toStateId 目标状态 ID
   * @param filter 可选：判断是否应响应此事件的函数
   */
  onEventTransition(
    event: string,
    toStateId: string,
    filter?: (fsm: FSM, eventData?: any) => boolean
  ): void {
    if (!this.eventTransitions.has(event)) {
      this.eventTransitions.set(event, []);
    }
    this.eventTransitions.get(event)!.push({
      event,
      toStateId,
      filter,
    });

    // 自动注册事件监听（假设 target 是 cc.EventTarget）
    if (this._target && this._target.on) {
      this._target.on(event, this.handleEvent, this);
    }
  }

  /**
   * 手动触发一个事件（可用于测试或外部调用）
   * @param event 事件名
   * @param eventData 事件数据
   */
  emit(event: string, eventData?: any): void {
    if (this._target && this._target.emit) {
      this._target.emit(event, eventData);
    } else {
      this.handleEvent(eventData, event);
    }
  }

  /**
   * 事件处理器
   */
  private handleEvent(eventData?: any, event?: string): void {
    if (!event) return;

    const transitions = this.eventTransitions.get(event);
    if (!transitions) return;

    for (const t of transitions) {
      if (t.filter && !t.filter(this, eventData)) continue;

      // 触发状态切换
      this.changeState(t.toStateId, false, eventData);
      break; // 找到第一个匹配就停止
    }
  }

  // ------------------ 更新逻辑 ------------------

  /**
   * 固定频率更新（建议 15~30 FPS）
   * 使用 schedule 实现
   */
  onEnable(): void {
    this.schedule(this.fixedUpdate.bind(this), 1 / 30);
  }

  onDisable(): void {
    this.unscheduleAllCallbacks();
  }

  /**
   * 固定更新主循环
   * 每帧调用，处理：
   * - 时间累计
   * - onUpdate
   * - 条件转移检查
   */
  private fixedUpdate(dt: number): void {
    if (!this._running || this._isPaused || this.isTransitioning) {
      return;
    }

    this.timeElapsed += dt;

    // 1. 更新当前状态
    if (this.curr) {
      const updateResult = this.curr.onUpdate(this, this.timeElapsed);
      if (updateResult instanceof Promise) {
        // 如果 onUpdate 是异步的，等待完成后再继续
        (async () => {
          try {
            await updateResult;
          } catch (e) {
            cc.error("[FSM] onUpdate 异常:", e);
          }
        })();
      }
    }

    // 2. 检查条件转移
    this.checkConditions();
  }

  /**
   * 检查所有条件转移规则，按优先级执行第一个满足的
   */
  private checkConditions(): void {
    for (const cond of this.conditions) {
      if (cond.condition(this)) {
        this.changeState(cond.toStateId);
        return;
      }
    }
  }

  // ------------------ 控制方法 ------------------

  pause(): void {
    this._isPaused = true;
  }

  resume(): void {
    this._isPaused = false;
  }

  setRunning(value: boolean): void {
    this._running = value;
  }

  /**
   * 判断是否处于某个状态
   * @param stateId 状态 ID
   * @returns 是否是当前状态
   */
  isInState(stateId: string): boolean {
    return this.curr?.id === stateId;
  }
}
